#ifndef _PHVEC3_H_
#define _PHVEC3_H_

#include <math.h>

class PHVEC3
{
public:

	// Used to allow the data in the vector to be accessed in different ways
	union
	{
		// Access the vector as an array
		float v[3];

		// Access the vector's individual components
		struct
		{
			float x;
			float y;
			float z;
		};
	};

	// Constructors
	PHVEC3(){ x = y = z = 0; }

	PHVEC3(float _x, float _y, float _z){ x = _x; y = _y; z = _z; }

	inline PHVEC3 operator+(const PHVEC3 &_phVec3) const
	{
		return PHVEC3(x + _phVec3.x, y + _phVec3.y, z + _phVec3.z);
	}
	
	inline PHVEC3 operator-(const PHVEC3 &_phVec3) const
	{
		return PHVEC3(x - _phVec3.x, y - _phVec3.y, z - _phVec3.z);
	}
	
	inline PHVEC3 operator*(const PHVEC3 &_phVec3) const
	{
		return PHVEC3(x * _phVec3.x, y * _phVec3.y, z * _phVec3.z);
	}
	
	inline PHVEC3 operator/(const PHVEC3 &_phVec3) const
	{
		return PHVEC3(x / _phVec3.x, y / _phVec3.y, z / _phVec3.z);
	}

	inline PHVEC3 operator+(float _fV) const
	{
		return PHVEC3(x + _fV, y + _fV, z + _fV);
	}

	inline PHVEC3 operator-(float _fV) const
	{
		return PHVEC3(x - _fV, y - _fV, z - _fV);
	}

	inline PHVEC3 operator/(float _fV) const
	{
		return PHVEC3(x / _fV, y / _fV, z / _fV);
	}

	inline PHVEC3 &operator=(const PHVEC3 &_phVec3)
	{
		x = _phVec3.x;
		y = _phVec3.y;
		z = _phVec3.z;
		return *this;
	}

	inline PHVEC3 &operator+=(const PHVEC3 &_phVec3)
	{
		x += _phVec3.x;
		y += _phVec3.y;
		z += _phVec3.z;
		return *this;
	}

	inline PHVEC3 &operator-=(const PHVEC3 &_phVec3)
	{
		x -= _phVec3.x;
		y -= _phVec3.y;
		z -= _phVec3.z;
		return *this;
	}

	inline PHVEC3 &operator*=(float _fV)
	{
		x *= _fV;
		y *= _fV;
		z *= _fV;
		return *this;
	}

	inline PHVEC3 &operator/=(float _fV)
	{
		x /= _fV;
		y /= _fV;
		z /= _fV;
		return *this;
	}

	inline PHVEC3 &MakeZero()
	{
		x = y = z = 0;
		return *this;
	}

	inline PHVEC3 &Negate()
	{
		x = -x;
		y = -y;
		z = -z;
		return *this;
	}

	inline float DotProduct(const PHVEC3 &_phVec3) const
	{
		return x * _phVec3.x + y * _phVec3.y + z * _phVec3.z;
	}

	inline friend float DotProduct(const PHVEC3 &_phA, const PHVEC3 &_phB)
	{
		return _phA.DotProduct(_phB);
	}

	inline friend void CrossProduct(PHVEC3 &_phOut, const PHVEC3 &_phA, const PHVEC3 &_phB)
	{
		_phOut.x = _phA.y * _phB.z - _phA.z * _phB.y;
		_phOut.y = _phA.z * _phB.x - _phA.x * _phB.z;
		_phOut.z = _phA.x * _phB.y - _phA.y * _phB.x;
	}

	inline friend PHVEC3 CrossProduct(const PHVEC3 &_phA, const PHVEC3 &_phB)
	{
		return PHVEC3((_phA.y * _phB.z - _phA.z * _phB.y), (_phA.z * _phB.x - _phA.x * _phB.z), (_phOut.z = _phA.x * _phB.y - _phA.y * _phB.x));
	}

	inline float Magnitude() const
	{
		return (float)sqrt(DotProduct(*this));
	}

	inline PHVEC3 &Normalize()
	{
		float _phInvMag = 1 / Magnitude();
		*this *= _phInvMag;
		return *this;
	}
};

#endif